package org.netbeans.gpx.visual.window;

import java.awt.BorderLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import org.netbeans.gpx.model.api.Selection;
import org.netbeans.gpx.model.api.Position;
import java.util.Collection;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.netbeans.api.settings.ConvertAsProperties;
import org.netbeans.gpx.visual.chart.AbstractChartBuilder;
import org.netbeans.gpx.visual.chart.ChartType;
import org.netbeans.gpx.visual.chart.ElevationChartBuilderFactory;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.util.Lookup;
import org.openide.util.LookupEvent;
import org.openide.util.LookupListener;
import org.openide.windows.TopComponent;
import org.openide.util.NbBundle.Messages;

/**
 * Top component which displays elevation profile.
 */
@ConvertAsProperties(
    dtd = "-//org.netbeans.gpx.visual//Elevation//EN",
autostore = false)
@TopComponent.Description(
    preferredID = "ElevationTopComponent",
iconBase = "org/netbeans/gpx/visual/resources/elevation.gif",
persistenceType = TopComponent.PERSISTENCE_ALWAYS)
@TopComponent.Registration(mode = "navigator", openAtStartup = false)
@ActionID(category = "Window", id = "org.netbeans.gpx.visual.window.ElevationTopComponent")
@ActionReference(path = "Menu/Window/GPX" /*, position = 333 */)
@TopComponent.OpenActionRegistration(
    displayName = "#CTL_ElevationAction",
preferredID = "ElevationTopComponent")
@Messages({
    "CTL_ElevationAction=Elevation",
    "CTL_ElevationTopComponent=Elevation Window",
    "HINT_ElevationTopComponent=This is a Elevation window"
})
public final class ElevationTopComponent extends TopComponent implements LookupListener, PropertyChangeListener {

    private static final long serialVersionUID = -7900084742185260837L;

    private Lookup.Result<Position> result;

    private Collection<? extends Position> points;

    private ChartType chartType;

    private ChartTypeChangeAction chartTypeChangeAction;

    private ChartPanel chartPanel;

    public ElevationTopComponent() {
        initComponents();
        setName(Bundle.CTL_ElevationTopComponent());
        setToolTipText(Bundle.HINT_ElevationTopComponent());

        points = new ArrayList<Position>();

        chartTypeChangeAction = new ChartTypeChangeAction();
        cmbElevationType.setAction(chartTypeChangeAction);

        chartType = (ChartType) cmbElevationType.getSelectedItem();
    }

    /**
     * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The
     * content of this method is always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        elevationPanel = new javax.swing.JPanel();
        cmbElevationType = new javax.swing.JComboBox();

        elevationPanel.setLayout(new java.awt.BorderLayout());

        cmbElevationType.setModel(new javax.swing.DefaultComboBoxModel(ChartType.values()));
        cmbElevationType.setBorder(javax.swing.BorderFactory.createLineBorder(javax.swing.UIManager.getDefaults().getColor("Button.shadow")));
        cmbElevationType.setRenderer(new ChartTypeRenderer());

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(elevationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
            .addGroup(layout.createSequentialGroup()
                .addComponent(cmbElevationType, javax.swing.GroupLayout.PREFERRED_SIZE, 196, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(0, 0, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addComponent(cmbElevationType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(elevationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 267, Short.MAX_VALUE))
        );
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JComboBox cmbElevationType;
    private javax.swing.JPanel elevationPanel;
    // End of variables declaration//GEN-END:variables

    @Override
    public void componentOpened() {
        chartTypeChangeAction.addPropertyChangeListener(this);

        result = Selection.Instance.getLookup().lookupResult(Position.class);
        result.addLookupListener(this);
        
        //Call once to 'resultChanged' to activate the listener
        resultChanged(new LookupEvent(result));
    }

    @Override
    public void componentClosed() {
        chartTypeChangeAction.removePropertyChangeListener(this);

        result.removeLookupListener(this);
        result = null;
    }

    void writeProperties(java.util.Properties p) {
        // better to version settings since initial version as advocated at
        // http://wiki.apidesign.org/wiki/PropertyFiles
        p.setProperty("version", "1.0");
        // TODO store your settings
    }

    void readProperties(java.util.Properties p) {
        String version = p.getProperty("version");
        // TODO read your settings according to their version
    }

    @Override
    public void resultChanged(LookupEvent le) {
        points = result.allInstances();

        updateChartPanel();
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        String propertyName = evt.getPropertyName();
        if (propertyName.equals(ChartType.class.getSimpleName())) {
            chartType = (ChartType) evt.getNewValue();
            updateChartPanel();
        }
    }

    private void updateChartPanel() {
        if (!points.isEmpty()) {

            JFreeChart chart = buildChart();

            if (chartPanel == null) {
                chartPanel = new ChartPanel(chart);
                elevationPanel.add(chartPanel, BorderLayout.CENTER);
            } else {
                chartPanel.setChart(chart);
            }
        }
    }

    private JFreeChart buildChart() {

        AbstractChartBuilder chartBuilder = ElevationChartBuilderFactory.getChartBuilder(chartType);
        return chartBuilder.buildChart(points);
    }
}
